from .relation_graph import EntityRelationGraph
from typing import Dict, List, Any
from rule import ruleAnalysis, rule, apply_rule, extra_rule
import json, re


class MockGenerator:
    def __init__(self, relation_graph: EntityRelationGraph):
        """
        初始化加权关系图
        :param relation_graph: 构建出来的加权关系图
        """
        self.grapth = relation_graph
        self.orderEntries = [
            relation_graph.entities[node_name]
            for node_name in relation_graph.get_proper_build_order()
        ]
        self.relations = relation_graph.relations

    def print_order(self):
        for i, entity in enumerate(self.orderEntries, 1):
            print(f"步骤 {i}: 表 {entity['name']}")
            print(f"  字段: {[f['field'] for f in entity['struts']]}")
            print(f"  描述: {entity.get('desc', '无')}")
            print(f"  模板: {entity.get('templates', '无')}")
            all_neighbors = self.grapth.get_reverse_neighbors(entity["name"])
            print(
                f"  依赖节点: {[] if not all_neighbors else [node_name[0] for node_name in all_neighbors]}"
            )
            print("-" * 40)
        print(f"  依赖关系: {self.relations}")

    def mock_data(self):
        result_data = {}
        # time_ranges 不可能为空，如果异常，取到的是今日
        for day in self.grapth.time_ranges:
            print(f"构建 {day} 基础数据")
            for i, entity in enumerate(self.orderEntries, 1):
                print(f"步骤 {i}: 表 {entity['name']}")
                # 获取依赖的节点
                all_neighbors = self.grapth.get_reverse_neighbors(entity["name"])
                entity["all_neighbors"] = (
                    []
                    if not all_neighbors
                    else [node_name[0] for node_name in all_neighbors]
                )

                # 获取表与表的依赖关系
                entity["all_relations"] = self._get_relations_to(entity["name"])

                # 构建节点数据
                self._mock_node(entity, day)

                # 当所有的节点全部构建完成，再去更新等待状态的节点
                if i == len(self.orderEntries):
                    self._finish_pending(day)

            result_data[day] = {}
            for i, entity in enumerate(self.orderEntries, 1):
                result_data[day][entity["name"]] = entity["data"]

        return result_data

    def _get_relations_to(self, target_table):
        return {
            key: rel for key, rel in self.relations.items() if key[1] == target_table
        }

    def _mock_node(self, entity: Dict[str, Any], day: str):
        # 实体中 data保存当前节点的mock数据
        # 获取节点模板
        node_templates: List = entity.get("templates", [])
        # 如果模板存在先使用模板填充所有的数据
        entity["data"] = node_templates.copy()
        # 关联关系更新关联的字段
        entity["data"] = self._relation_merge(entity)
        # 规则生成节点mock数据
        entity["data"] = self._rule_generate(entity, day)
        # 如果存在等待规则生成的字段，进行补全
        if entity["rule_pending"]:
            self._finish_rule_generate(entity, day)

    def _rule_generate(self, entity: Dict[str, Any], day: str):
        entity["rule_pending"] = False
        entity["rule_pending_field"] = []
        basic_datas: List = entity.get("data", [])
        struts = entity["struts"]
        # Step 1: 应用规则，生成 rule_data {field: value}
        rule_data_list: List[Dict[str, Any]] = []
        rule_data: Dict[str, Any] = {}
        need_regenrate = {}
        for item in struts:
            rule_regx: str = item["rule"]
            field: str = item["field"]
            if rule_regx.startswith("extra@"):
                # 这边判断下 是否需要等待字段后期更新
                # 使用正则提取 select[xxx] 中的 xxx
                match = re.search(r"select\[(.*?)\]", rule_regx)
                if match:
                    select_field = match.group(1).strip()
                    # print(f"Extracted select field: {select_field}")
                    value = rule_data.get(select_field)
                    if value is None or type(value) != "str" or value == "":
                        entity["rule_pending"] = True
                        entity["rule_pending_field"].append(field)
                        rule_content = ""
                    else:
                        rule_content = extra_rule(
                            self.grapth.extra_datas[day], f"{rule_regx}@{value}"
                        )
                else:
                    rule_content = extra_rule(self.grapth.extra_datas[day], rule_regx)
            elif rule_regx.startswith("apply@"):
                # apply_rule 支持 apply@date... 或 apply@str...
                rule_content = apply_rule(day, rule_regx, ruleAnalysis)
            else:
                if rule_regx:
                    need_regenrate[field] = rule_regx
                rule_content = rule(rule_regx, ruleAnalysis)

            rule_data[field] = rule_content

        # Step 2: 检查哪些字段是列表（非字符串！注意：字符串也是 iterable）
        list_fields = []
        scalar_fields = []
        max_len = 0

        for field, value in rule_data.items():
            # 判断是否为非字符串的 list/tuple
            if isinstance(value, (list, tuple)) and not isinstance(value, str):
                list_fields.append(field)
                max_len = max(max_len, len(value))
            else:
                scalar_fields.append(field)

        # Step 3: 按 max_len 展开，生成多条记录
        if max_len > 0:
            for i in range(max_len):
                new_record = {}
                # 处理列表字段：取第 i 个元素，若越界则为空字符串或 None
                for field in list_fields:
                    val_list = rule_data[field]
                    if i < len(val_list):
                        new_record[field] = val_list[i]
                    else:
                        new_record[field] = ""  # 或 None，根据业务需求
                # 处理标量字段：直接复制
                for field in scalar_fields:
                    new_record[field] = rule_data[field]

                rule_data_list.append(new_record)
        else:
            rule_data_list.append(rule_data)

        # Step 4: rule_data_list 和 基础数据 归并
        final_records = []

        if not basic_datas:
            # 无基础数据，直接使用规则生成的数据
            final_records = rule_data_list
        else:
            for basic_data in basic_datas:
                # 添加基础数据（若存在）
                for rule_data in rule_data_list:
                    merged = {**basic_data, **self._non_empty_items(rule_data)}
                    # 对于模板的笛卡尔积 对应的通用规则需要重新遍历生成
                    for field in scalar_fields:
                        if field in need_regenrate.keys():
                            merged[field] = rule(need_regenrate[field], ruleAnalysis)

                    final_records.append(merged)

        return final_records

    def _finish_rule_generate(self, entity: Dict[str, Any], day: str):
        basic_datas: List = entity.get("data", [])
        final_result = []
        rule_pending_field: List = entity.get("rule_pending_field", [])
        struts = entity["struts"]
        need_regenrate = {}
        for item in struts:
            rule_regx: str = item["rule"]
            field: str = item["field"]
            if field not in rule_pending_field:
                if not rule_regx.startswith("extra@") and not rule_regx.startswith("apply@") and rule_regx:
                    need_regenrate[field] = rule_regx
                    continue

            for rule_data in basic_datas:
                if rule_regx.startswith("extra@"):
                    # 这边判断下 是否需要等待字段后期更新
                    # 使用正则提取 select[xxx] 中的 xxx
                    match = re.search(r"select\[(.*?)\]", rule_regx)
                    if match:
                        select_field = match.group(1).strip()  # 得到 'ASSET_ID'
                        # print(f"Extracted select field: {select_field}")
                        value = rule_data.get(select_field)
                        if value is None or value == "":
                            rule_content = ""
                        else:
                            rule_content = extra_rule(
                                self.grapth.extra_datas[day], f"{rule_regx}@{value}"
                            )
                    else:
                        rule_content = extra_rule(
                            self.grapth.extra_datas[day], rule_regx
                        )
                elif rule_regx.startswith("apply@"):
                    # apply_rule 支持 apply@date... 或 apply@str...
                    rule_content = apply_rule(day, rule_regx, ruleAnalysis)
                else:
                    need_regenrate[field] = rule_regx
                    rule_content = rule(rule_regx, ruleAnalysis)

                rule_data[field] = rule_content

        for rule_data in basic_datas:
            list_fields = []
            scalar_fields = []
            max_len = 0

            for field, value in rule_data.items():
                # 判断是否为非字符串的 list/tuple
                if isinstance(value, (list, tuple)) and not isinstance(value, str):
                    list_fields.append(field)
                    max_len = max(max_len, len(value))
                else:
                    scalar_fields.append(field)

            # Step 3: 按 max_len 展开，生成多条记录
            if max_len > 0:
                for i in range(max_len):
                    new_record = {}
                    # 处理列表字段：取第 i 个元素，若越界则为空字符串或 None
                    for field in list_fields:
                        val_list = rule_data[field]
                        if i < len(val_list):
                            new_record[field] = val_list[i]
                        else:
                            new_record[field] = ""  # 或 None，根据业务需求
                    # 处理标量字段：直接复制，对于常规规则就重新生成
                    for field in scalar_fields:
                        if field in need_regenrate.keys():
                            new_record[field] = rule(
                                need_regenrate[field], ruleAnalysis
                            )
                        else:
                            new_record[field] = rule_data[field]

                    final_result.append(new_record)
            else:
                final_result.append(rule_data)

        entity["data"] = final_result

    def _relation_merge(self, entity):
        # 获取实体所引用的表
        entity["pending"] = False
        entity["pendingTable"] = []
        entity_name = entity["name"]
        entity_data_list = entity["data"]
        neighbors: List[str] = entity["all_neighbors"]
        relations: tuple = entity["all_relations"]
        final_data_list = []
        if len(neighbors) == 0:
            final_data_list.extend(entity_data_list)
        else:
            sorted_neighbors = sorted(
                neighbors,
                key=lambda table: len(self.grapth.entities[table].get("data") or []),
                reverse=True,  # 降序：长的在前
            )
            for table_name in sorted_neighbors:
                if len(final_data_list) > 0:
                    entity_data_list = final_data_list
                    final_data_list = []

                # 根据table 获取entity
                neighbor_entity: Dict[str, Any] = self.grapth.entities[table_name]
                relation_key = (table_name, entity_name)
                field_relations: List[Dict[str, str]] = relations[relation_key]["on"]

                neighbor_entity_data_list: List[Dict[str, Any]] = (
                    neighbor_entity["data"] or []
                )
                if len(neighbor_entity_data_list) == 0:
                    entity["pending"] = True
                    pendingTable: List[str] = entity["pendingTable"]
                    pendingTable.append(table_name)
                    continue

                # 判断neighbor_entity_data_list 是否已经存在
                # 依赖的节点数据已经构建 根据left_field 和 right_field 去拷贝字段数据
                for neighbor_entity_data in neighbor_entity_data_list:
                    for entity_data in entity_data_list:
                        merged = {}
                        merged.update(entity_data)
                        for field_relation in field_relations:
                            neighbor_field = field_relation["left_field"]
                            entity_field = field_relation["right_field"]
                            merged[entity_field] = neighbor_entity_data[neighbor_field]
                        final_data_list.append(merged)

        return final_data_list

    def _finish_relation_merge(self, entity):
        # 获取实体所引用的表
        entity_name = entity["name"]
        entity_data_list = entity["data"]
        relations: tuple = entity["all_relations"]
        final_data_list = []
        for table_name in entity["pendingTable"]:
            # 根据table 获取entity
            neighbor_entity = self.grapth.entities[table_name]
            relation_key = (table_name, entity_name)
            field_relations: List[Dict[str, str]] = relations[relation_key]["on"]

            neighbor_entity_data_list: List[Dict[str, Any]] = (
                neighbor_entity["data"] or []
            )
            # 判断neighbor_entity_data_list 是否已经存在
            # 依赖的节点数据已经构建 根据left_field 和 right_field 去拷贝字段数据
            for neighbor_entity_data in neighbor_entity_data_list:
                for entity_data in entity_data_list:
                    merged = {}
                    merged.update(entity_data)
                    for field_relation in field_relations:
                        neighbor_field = field_relation["left_field"]
                        entity_field = field_relation["right_field"]
                        merged[entity_field] = neighbor_entity_data[neighbor_field]
                    final_data_list.append(merged)

        entity["data"] = final_data_list

    def _finish_pending(self, day: str):
        for i, entity in enumerate(self.orderEntries, 1):

            if entity["pending"]:
                self._finish_relation_merge(entity)

    def _non_empty_items(self, d: dict) -> dict:
        """返回字典中所有“非空”键值对"""
        return {
            k: v
            for k, v in d.items()
            if v is not None and v != "" and (not isinstance(v, str) or v.strip())
        }


__all__ = ["MockGenerator"]
